#include "DockerClient.h"
#include <cpprest/filestream.h>
#include <stdio.h>
// #include <string>
// #include <iostream>

using namespace NSDockerClient;

int main(int argc, const char **argv)
{
    DockerClient docker_client("127.0.0.1", 4243);

    NSDockerClient::TDDockerQueryFilters Filters;    
    // Filters.insert(std::make_pair("before", "redis:latest"));
    // Filters.insert(std::make_pair("dangling", "false"));
    docker_client.ListImages(false, false, &Filters, [](bool bRR, std::vector<SDockerImage> &vecDImage, std::string &ErrorString) {
        if (!bRR)
        {
            printf("List Images Error: %s\n", ErrorString.c_str());
            return;
        }
        for (int i = 0; i < vecDImage.size(); ++i)
        {
            printf("Image[%d]: ID=\"%s\", ParentID=\"%s\", CreatedTimestamp=%lld, Size=%lld, SharedSize=%lld, VirtualSize=%lld, ContainerNum=%lld\n",
                i,
                vecDImage[i].ID.c_str(), vecDImage[i].ParentID.c_str(), vecDImage[i].CreatedTimestamp,
                vecDImage[i].Size, vecDImage[i].SharedSize, vecDImage[i].VirtualSize, vecDImage[i].ContainerNum);
            printf("\tRepoTags\n");
            for (int j = 0; j < vecDImage[i].RepoTags.size(); ++j)
                printf("\t\t%s\n", vecDImage[i].RepoTags[j].c_str());
            printf("\tRepoDigests\n");
            for (int j = 0; j < vecDImage[i].RepoDigests.size(); ++j)
                printf("\t\t%s\n", vecDImage[i].RepoDigests[j].c_str());
        }
    });
    // usleep(1000 * 100);
    // printf("Import Image...\n");
    // auto ifs = concurrency::streams::fstream::open_istream("/home/yingxd/share/Projects/01_C_CPP/DockerClient/xxx.tar").get();
    // docker_client.ImportImage(ifs, [](bool bRR, std::string &Repository, std::string &Tag, std::string &ErrorString) {
    //     if (!bRR)
    //     {
    //         printf("Import Image Error: %s\n", ErrorString.c_str());
    //         return;
    //     }
    //     printf("Import Image: /home/yingxd/share/Projects/01_C_CPP/DockerClient/xxx.tar\n%s:%s\n", Repository.c_str(), Tag.c_str());
    // });
    // usleep(1000 * 100);
    // printf("Export Image(wssdkserv:3.1.10.demo)...\n");
    // docker_client.ExportImage("wssdkserv:3.1.10.demo", [](bool bRR, void *tarball, size_t tb_size, std::string &ErrorString) {
    //     if (!bRR)
    //     {
    //         printf("Export Image Error: %s\n", ErrorString.c_str());
    //         return;
    //     }
    //     if (access("/home/yingxd/share/Projects/01_C_CPP/DockerClient/test.tar", F_OK) == 0) return;
    //     std::ofstream ofs("/home/yingxd/share/Projects/01_C_CPP/DockerClient/test.tar", std::ios::binary);
    //     ofs.write((char*)tarball, tb_size);
    //     ofs.close();
    //     printf("Export Image: /home/yingxd/share/Projects/01_C_CPP/DockerClient/test.tar\n");
    // });
    // usleep(1000 * 100);
    // docker_client.RemoveImage("0ba31183f4cf", [](bool bRR, std::string &ErrorString) {
    //     if (!bRR)
    //     {
    //         printf("Remove Image Error: %s\n", ErrorString.c_str());
    //         return;
    //     }
    //     printf("Removed Image: 0ba31183f4cf\n");
    // });
    usleep(1000 * 100);
    Filters.clear();
    // Filters.insert(std::make_pair("status", "exited"));
    // Filters.insert(std::make_pair("since", "dfc3a867b49cc10a0927f25abc2fb6a1927c3b5219ad55a116be14d8de25d2f1"));
    docker_client.ListContainers(true, 10, true, &Filters, [](bool bRR, std::vector<SDockerContainer> &vecDContainer, std::string &ErrorString) {
        if (!bRR)
        {
            printf("List Containsers Error: %s\n", ErrorString.c_str());
            return;
        }
        for (int i = 0; i < vecDContainer.size(); ++i)
        {
            printf("Containers[%d]: ID=\"%s\", Image=\"%s\", ImageID=\"%s\", Command=\"%s\", State=\"%s\", Status=\"%s\", HostNetworkMode=\"%s\", "
                "CreatedTimestamp=%lld, SizeRw=%lld, SizeRootFs=%lld\n",
                i,
                vecDContainer[i].ID.c_str(), vecDContainer[i].Image.c_str(), vecDContainer[i].ImageID.c_str(), vecDContainer[i].Command.c_str(),
                vecDContainer[i].State.c_str(), vecDContainer[i].Status.c_str(), vecDContainer[i].HostConfig.NetworkMode.c_str(),
                vecDContainer[i].CreatedTimestamp,
                vecDContainer[i].SizeRw, vecDContainer[i].SizeRootFs);
            printf("\tNames\n");
            for (int j = 0; j < vecDContainer[i].Names.size(); ++j)
                printf("\t\t%s\n", vecDContainer[i].Names[j].c_str());
            printf("\tPorts\n");
            for (int j = 0; j < vecDContainer[i].MapPorts.size(); ++j)
                printf("\t\tType=%s, PublicIP=%s, PublicPort=%d, PrivatePort=%d\n", vecDContainer[i].MapPorts[j].Type.c_str(), vecDContainer[i].MapPorts[j].PublicIP.c_str(),
                    vecDContainer[i].MapPorts[j].PublicPort, vecDContainer[i].MapPorts[j].PrivatePort);
        }
    });
    usleep(1000 * 100);
    docker_client.InspectContainer("mysql_8.0.28_devel", true,
        [](bool bRR, SDockerContainer &DContainer, std::string &ErrorString) {
        if (!bRR)
        {
            printf("Inspect Containser Error: %s\n", ErrorString.c_str());
            return;
        }
        printf("Containers[%s]: ID=\"%s\", Image=\"%s\", ImageID=\"%s\", Command=\"%s\", State=\"%s\", Status=\"%s\", HostNetworkMode=\"%s\", "
            "CreatedTimestamp=%lld, SizeRw=%lld, SizeRootFs=%lld\n",
            DContainer.ID.c_str(),
            DContainer.ID.c_str(), DContainer.Image.c_str(), DContainer.ImageID.c_str(), DContainer.Command.c_str(),
            DContainer.State.c_str(), DContainer.Status.c_str(), DContainer.HostConfig.NetworkMode.c_str(),
            DContainer.CreatedTimestamp,
            DContainer.SizeRw, DContainer.SizeRootFs);
        printf("\tHostPortBindings\n");
        for (auto itr = DContainer.HostConfig.PortBindings.begin(); itr != DContainer.HostConfig.PortBindings.end(); ++itr)
        {
            printf("\t\t%s: ", (itr->first.Type + "/" + std::to_string(itr->first.Port)).c_str());
            for (int j = 0; j < itr->second.size(); ++j)
                printf("%s:%d, ", itr->second[j].IP.c_str(), itr->second[j].Port);
            printf("\n");
        }
        printf("\tExposedPorts\n");
        for (auto &ep : DContainer.ExposedPorts)
            printf("\t\t%s\n", (ep.Type + "/" + std::to_string(ep.Port)).c_str());
        printf("\tNames\n");
        for (int j = 0; j < DContainer.Names.size(); ++j)
            printf("\t\t%s\n", DContainer.Names[j].c_str());
        printf("\tPorts\n");
        for (int j = 0; j < DContainer.MapPorts.size(); ++j)
            printf("\t\tType=%s, PublicIP=%s, PublicPort=%d, PrivatePort=%d\n", DContainer.MapPorts[j].Type.c_str(), DContainer.MapPorts[j].PublicIP.c_str(),
                DContainer.MapPorts[j].PublicPort, DContainer.MapPorts[j].PrivatePort);
    });
    // usleep(1000 * 100);
    // docker_client.ProcessStatusInsideContainer("recursing_buck", "-aux", [](bool bRR, SDockerContainerProcessStatus &PS, std::string &ErrorString) {
    //     if (!bRR)
    //     {
    //         printf("PS Error: %s\n", ErrorString.c_str());
    //         return;
    //     }
    //     for (int i = 0; i < PS.Titles.size(); ++i)
    //     {
    //         printf("%s ", PS.Titles[i].c_str());
    //     }
    //     printf("\n");
    //     for (int i = 0; i < PS.vecPS.size(); ++i)
    //     {
    //         for (int j = 0; j < PS.vecPS[i].size(); ++j)
    //         {
    //             printf("%s ", PS.vecPS[i][j].c_str());
    //         }
    //         printf("\n");
    //     }
    // });
    // usleep(2000 * 100);
    // docker_client.StartContainer("recursing_buck", [](bool bRR, std::string &ErrorString) {
    //     if (bRR)
    //     {
    //         printf("Start OK(%s)\n", ErrorString.c_str());
    //     }
    //     else
    //     {
    //         printf("Start Error: %s\n", ErrorString.c_str());
    //     }
    // });
    // docker_client.StopContainer("recursing_buck", [](bool bRR, std::string &ErrorString) {
    //     if (bRR)
    //     {
    //         printf("Stop OK(%s)\n", ErrorString.c_str());
    //     }
    //     else
    //     {
    //         printf("Stop Error: %s\n", ErrorString.c_str());
    //     }
    // });
    // docker_client.RestartContainer("recursing_buck", [](bool bRR, std::string &ErrorString) {
    //     if (bRR)
    //     {
    //         printf("Restart OK\n");
    //     }
    //     else
    //     {
    //         printf("Restart Error: %s\n", ErrorString.c_str());
    //     }
    // });
    // docker_client.KillContainer("recursing_buck", "", [](bool bRR, std::string &ErrorString) {
    //     if (bRR)
    //     {
    //         printf("Kill OK\n");
    //     }
    //     else
    //     {
    //         printf("Kill Error: %s\n", ErrorString.c_str());
    //     }
    // });
    // SDockerContainerRemove Rv;
    // docker_client.RemoveContainer("ws3", Rv, [](bool bRR, std::string &ErrorString) {
    //     if (bRR)
    //     {
    //         printf("Remove OK\n");
    //     }
    //     else
    //     {
    //         printf("Remove Error: %s\n", ErrorString.c_str());
    //     }
    // });
    // usleep(1000 * 100);
    // SDockerContainerCreation DCC;
    // DCC.Name = "ws3";
    // DCC.Image = "wssdkserv:3.1.10.demo";
    // // DCC.WorkingDir = "/XXX";
    // DCC.Envs.push_back("X=12");
    // DCC.Envs.push_back("Y=3");
    // DCC.Envs.push_back("BB=FEW");
    // DCC.ExposedPorts.push_back(SDockerPortDescript());
    // DCC.ExposedPorts.back().Port = 3112;
    // DCC.ExposedPorts.back().Type = "tcp";
    // DCC.ExposedPorts.push_back(SDockerPortDescript());
    // DCC.ExposedPorts.back().Port = 3113;
    // DCC.ExposedPorts.back().Type = "udp";
    // DCC.ExposedPorts.push_back(SDockerPortDescript());
    // DCC.ExposedPorts.back().Port = 3115;
    // DCC.ExposedPorts.back().Type = "tcp";
    // // DCC.HostConfig.Binds.push_back(SDockerDirectoryBind("/home/yingxd/share/Projects/01_C_CPP/DockerClient/test", "/XXX", SDockerDirectoryBind::EMode::mRead));
    // // DCC.HostConfig.Binds.push_back(SDockerDirectoryBind("vl_test", "/yyy", SDockerDirectoryBind::EMode::mReadWrite | SDockerDirectoryBind::EMode::mNoCopy));
    // DCC.HostConfig.NetworkMode = "bridge";
    // // DCC.HostConfig.IPCMode = "host";
    // // DCC.HostConfig.PIDMode = "host";
    // SDockerPortDescript PD;
    // SDockerIPPortDescript IPD;
    // std::vector<SDockerIPPortDescript> VIPD;
    // PD.Port = 3112;
    // PD.Type = "tcp";
    // IPD.IP = "127.0.0.1";
    // IPD.Port = 3112;
    // VIPD.push_back(IPD);
    // DCC.HostConfig.PortBindings.insert(std::make_pair(PD, VIPD));
    // VIPD.clear();
    // PD.Port = 3113;
    // PD.Type = "udp";
    // IPD.IP = "127.0.0.1";
    // IPD.Port = 3113;
    // VIPD.push_back(IPD);
    // DCC.HostConfig.PortBindings.insert(std::make_pair(PD, VIPD));
    // VIPD.clear();
    // PD.Port = 3115;
    // PD.Type = "tcp";
    // IPD.IP = "127.0.0.1";
    // IPD.Port = 3115;
    // VIPD.push_back(IPD);
    // PD.Port = 3115;
    // PD.Type = "tcp";
    // IPD.IP = "127.0.0.1";
    // IPD.Port = 22253;
    // VIPD.push_back(IPD);
    // DCC.HostConfig.PortBindings.insert(std::make_pair(PD, VIPD));
    // docker_client.CreateContainer(DCC, [](bool bRR, SDockerContainerCreationResult &CR, std::string &ErrorString) {
    //     if (!bRR)
    //     {
    //         printf("Create Container Error: %s\n", ErrorString.c_str());
    //         return;
    //     }
    //     printf("DID:%s\nWarning\n", CR.ID.c_str());
    //     for (int i = 0; i < CR.Warnings.size(); ++i)
    //     {
    //         printf("\t%s\n", CR.Warnings[i].c_str());
    //     }
    // });
    usleep(1000 * 100);
    Filters.clear();
    // Filters.insert(std::make_pair("name", "24a864c9501f0296c230ba7701417ebe4e547518a4def080043b19c0c3d05187"));
    // Filters.insert(std::make_pair("dangling", "true"));
    docker_client.ListVolumes(&Filters, [](bool bRR, std::vector<SDockerVolume> &vecDVolume, std::string &ErrorString) {
        if (!bRR)
        {
            printf("List Volumes Error: %s\n", ErrorString.c_str());
            return;
        }
        for (int i = 0; i < vecDVolume.size(); ++i)
        {
            printf("Volumes[%d]: Name=\"%s\", Driver=\"%s\", Mountpoint=\"%s\", Scope=\"%s\", CreatedTimestamp=%lld\n",
                i,
                vecDVolume[i].Name.c_str(), vecDVolume[i].Driver.c_str(), vecDVolume[i].Mountpoint.c_str(), vecDVolume[i].Scope.c_str(),
                vecDVolume[i].CreatedTimestamp);
        }
    });
    // usleep(1000 * 100);
    // SDockerVolumeCreation DVC;
    // DVC.Name = "test_volume1";
    // docker_client.CreateVolume(DVC, [](bool bRR, SDockerVolumeCreationResult &CR, std::string &ErrorString) {
    //     if (!bRR)
    //     {
    //         printf("Create Volume Error: %s\n", ErrorString.c_str());
    //         return;
    //     }
    //     printf("Create Volume: Name=%s, Driver=%s, Mountpoint=%s, Scope=%s, CreatedTimestamp=%lld\nOptions: ", CR.Name.c_str(), CR.Driver.c_str(), CR.Mountpoint.c_str(), CR.Scope.c_str(),
    //         CR.CreatedTimestamp);
    //     for (auto &opt : CR.Options)
    //         printf("%s=%s, ", opt.first.c_str(), opt.second.c_str());
    //     printf("\nLabels: ");
    //     for (auto &lb : CR.Labels)
    //         printf("%s=%s, ", lb.first.c_str(), lb.second.c_str());
    //     printf("\nStatus: ");
    //     for (auto &st : CR.Status)
    //         printf("%s=%s, ", st.first.c_str(), st.second.c_str());
    //     printf("\n");
    // });
    // usleep(1000 * 100);
    // docker_client.RemoveVolume("test_volume1", false, [](bool bRR, std::string &ErrorString) {
    //     if (!bRR)
    //     {
    //         printf("Remove Volume Error: %s\n", ErrorString.c_str());
    //         return;
    //     }
    //     printf("Remove Volume OK\n");
    // });
    usleep(1000 * 100);
    Filters.clear();
    // Filters.insert(std::make_pair("driver", "bridge"));
    // Filters.insert(std::make_pair("dangling", "true"));
    docker_client.ListNetWorks(&Filters, [](bool bRR, std::vector<SDockerNetWork> &vecDNetWork, std::string &ErrorString) {
        if (!bRR)
        {
            printf("List NetWork Error: %s\n", ErrorString.c_str());
            return;
        }
        for (int i = 0; i < vecDNetWork.size(); ++i)
        {
            printf("NetWork[%d]: ID=\"%s\", Name=\"%s\", Driver=\"%s\", Scope=\"%s\", CreatedTimestamp=%lld, EnableIPv6=%d, Internal=%d, Attachable=%d, Ingress=%d\n",
                i,
                vecDNetWork[i].ID.c_str(), vecDNetWork[i].Name.c_str(), vecDNetWork[i].Driver.c_str(), vecDNetWork[i].Scope.c_str(),
                vecDNetWork[i].CreatedTimestamp,
                vecDNetWork[i].EnableIPv6, vecDNetWork[i].Internal, vecDNetWork[i].Attachable, vecDNetWork[i].Ingress);
        }
    });

    pause();
    return 0;
}